package com.apigen.platform.service.impl;

import com.apigen.platform.dto.CodeGenerationRequest;
import com.apigen.platform.entity.GenTable;
import com.apigen.platform.entity.GenTableField;
import com.apigen.platform.entity.GenApiEndpoint;
import com.apigen.platform.mapper.GenTableMapper;
import com.apigen.platform.mapper.GenTableFieldMapper;
import com.apigen.platform.mapper.GenApiEndpointMapper;
import com.apigen.platform.service.ICodeGenerationService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 代码生成服务实现类
 *
 * @author API Generator Platform
 * @since 2024-09-24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CodeGenerationServiceImpl implements ICodeGenerationService {

    private final GenTableMapper genTableMapper;
    private final GenTableFieldMapper genTableFieldMapper;
    private final GenApiEndpointMapper apiEndpointMapper;

    @Override
    public Map<String, Object> generateProject(CodeGenerationRequest request) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 验证生成配置
            Map<String, Object> validationResult = validateConfig(request);
            if (!(Boolean) validationResult.get("valid")) {
                return validationResult;
            }

            // 2. 获取表和字段信息
            List<TableInfo> tables = getTableInfoList(request.getTableIds());
            if (tables.isEmpty()) {
                result.put("success", false);
                result.put("message", "未找到要生成的表信息");
                return result;
            }

            // 3. 获取API端点信息
            List<ApiEndpointInfo> endpoints = getApiEndpointList(request.getProjectId(), request.getTableIds());

            // 4. 根据框架类型生成代码
            Map<String, String> generatedFiles = generateCodeFiles(request, tables, endpoints);

            // 5. 创建项目压缩包
            String downloadUrl = createProjectArchive(request.getProjectCode(), generatedFiles);

            // 6. 保存生成记录
            Long generationId = saveGenerationRecord(request, tables.size(), endpoints.size());

            result.put("success", true);
            result.put("message", "代码生成成功");
            result.put("generationId", generationId);
            result.put("downloadUrl", downloadUrl);
            result.put("projectName", request.getProjectName());
            result.put("fileCount", generatedFiles.size());
            result.put("tableCount", tables.size());
            result.put("endpointCount", endpoints.size());
            result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

            log.info("项目{}代码生成成功，共生成{}个文件", request.getProjectName(), generatedFiles.size());

        } catch (Exception e) {
            log.error("代码生成失败: {}", e.getMessage(), e);
            result.put("success", false);
            result.put("message", "代码生成失败: " + e.getMessage());
        }

        return result;
    }

    @Override
    public Map<String, Object> previewCode(CodeGenerationRequest request) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取表信息（仅取第一张表作为预览）
            List<TableInfo> tables = getTableInfoList(request.getTableIds().subList(0, Math.min(1, request.getTableIds().size())));
            if (tables.isEmpty()) {
                result.put("success", false);
                result.put("message", "未找到表信息");
                return result;
            }

            TableInfo table = tables.get(0);
            
            // 生成预览文件
            Map<String, String> previewFiles = new HashMap<>();
            
            if (request.getConfig().getGenerateEntity()) {
                previewFiles.put("Entity.java", generateEntityCode(request, table));
            }
            if (request.getConfig().getGenerateDto()) {
                previewFiles.put("DTO.java", generateDtoCode(request, table));
            }
            if (request.getConfig().getGenerateController()) {
                previewFiles.put("Controller.java", generateControllerCode(request, table));
            }
            if (request.getConfig().getGenerateService()) {
                previewFiles.put("Service.java", generateServiceCode(request, table));
            }

            result.put("success", true);
            result.put("previewFiles", previewFiles);
            result.put("tableName", table.getTableName());
            result.put("tableComment", table.getTableComment());

        } catch (Exception e) {
            log.error("代码预览失败: {}", e.getMessage());
            result.put("success", false);
            result.put("message", "代码预览失败: " + e.getMessage());
        }

        return result;
    }

    @Override
    public Map<String, Object> getSupportedFrameworks() {
        Map<String, Object> frameworks = new HashMap<>();
        
        // Spring Boot框架
        Map<String, Object> springBoot = new HashMap<>();
        springBoot.put("name", "Spring Boot");
        springBoot.put("description", "企业级Java Web框架");
        springBoot.put("version", "2.7.x");
        springBoot.put("language", "Java");
        springBoot.put("features", Arrays.asList("Spring Security", "MyBatis Plus", "Knife4j", "Redis", "MySQL"));
        frameworks.put("SPRING_BOOT", springBoot);

        // Express框架
        Map<String, Object> express = new HashMap<>();
        express.put("name", "Express.js");
        express.put("description", "Node.js Web应用框架");
        express.put("version", "4.x");
        express.put("language", "JavaScript");
        express.put("features", Arrays.asList("JWT", "Mongoose", "Swagger", "Redis", "MongoDB"));
        frameworks.put("EXPRESS", express);

        // FastAPI框架
        Map<String, Object> fastapi = new HashMap<>();
        fastapi.put("name", "FastAPI");
        fastapi.put("description", "现代Python Web框架");
        fastapi.put("version", "0.100.x");
        fastapi.put("language", "Python");
        fastapi.put("features", Arrays.asList("SQLAlchemy", "Pydantic", "JWT", "Redis", "PostgreSQL"));
        frameworks.put("FASTAPI", fastapi);

        return frameworks;
    }

    @Override
    public Map<String, Object> getTemplateConfig(String frameworkType) {
        Map<String, Object> config = new HashMap<>();
        
        switch (frameworkType.toUpperCase()) {
            case "SPRING_BOOT":
                config.put("defaultPort", 8080);
                config.put("defaultDatabase", "MySQL");
                config.put("requiredDependencies", Arrays.asList("spring-boot-starter-web", "mybatis-plus-boot-starter", "mysql-connector-java"));
                config.put("optionalFeatures", Arrays.asList("Redis", "Security", "Swagger", "Docker"));
                break;
            case "EXPRESS":
                config.put("defaultPort", 3000);
                config.put("defaultDatabase", "MongoDB");
                config.put("requiredDependencies", Arrays.asList("express", "mongoose", "jsonwebtoken"));
                config.put("optionalFeatures", Arrays.asList("Redis", "Swagger", "Docker"));
                break;
            case "FASTAPI":
                config.put("defaultPort", 8000);
                config.put("defaultDatabase", "PostgreSQL");
                config.put("requiredDependencies", Arrays.asList("fastapi", "sqlalchemy", "psycopg2"));
                config.put("optionalFeatures", Arrays.asList("Redis", "JWT", "Docker"));
                break;
            default:
                config.put("error", "不支持的框架类型: " + frameworkType);
        }
        
        return config;
    }

    @Override
    public Map<String, Object> validateConfig(CodeGenerationRequest request) {
        Map<String, Object> result = new HashMap<>();
        List<String> errors = new ArrayList<>();

        // 验证基础参数
        if (!StringUtils.hasText(request.getProjectName())) {
            errors.add("项目名称不能为空");
        }
        if (!StringUtils.hasText(request.getProjectCode())) {
            errors.add("项目编码不能为空");
        }
        if (!StringUtils.hasText(request.getPackageName())) {
            errors.add("包名不能为空");
        }
        if (request.getTableIds() == null || request.getTableIds().isEmpty()) {
            errors.add("必须选择至少一张表");
        }

        // 验证数据库配置
        if (request.getConfig() != null && request.getConfig().getDatabase() != null) {
            CodeGenerationRequest.DatabaseConfig dbConfig = request.getConfig().getDatabase();
            if (!StringUtils.hasText(dbConfig.getDatabase())) {
                errors.add("数据库名不能为空");
            }
        }

        result.put("valid", errors.isEmpty());
        result.put("errors", errors);
        if (!errors.isEmpty()) {
            result.put("success", false);
            result.put("message", "配置验证失败: " + String.join(", ", errors));
        }

        return result;
    }

    @Override
    public Map<String, Object> getGenerationHistory(Long projectId, Long current, Long size) {
        // TODO: 实现生成历史记录查询
        Map<String, Object> result = new HashMap<>();
        result.put("records", new ArrayList<>());
        result.put("total", 0);
        result.put("current", current);
        result.put("size", size);
        return result;
    }

    @Override
    public Map<String, Object> downloadGeneratedCode(Long generationId) {
        // TODO: 实现代码包下载
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("message", "下载功能待实现");
        return result;
    }

    /**
     * 获取表信息列表
     */
    private List<TableInfo> getTableInfoList(List<Long> tableIds) {
        List<TableInfo> tables = new ArrayList<>();
        
        for (Long tableId : tableIds) {
            GenTable genTable = genTableMapper.selectById(tableId);
            if (genTable == null) {
                continue;
            }

            // 获取字段信息
            LambdaQueryWrapper<GenTableField> fieldQuery = new LambdaQueryWrapper<>();
            fieldQuery.eq(GenTableField::getTableId, tableId)
                     .orderByAsc(GenTableField::getSortOrder);
            List<GenTableField> fields = genTableFieldMapper.selectList(fieldQuery);

            TableInfo tableInfo = new TableInfo();
            tableInfo.setTableId(tableId);
            tableInfo.setTableName(genTable.getTableName());
            tableInfo.setTableComment(genTable.getTableComment());
            tableInfo.setFields(fields.stream().map(this::convertToFieldInfo).collect(Collectors.toList()));
            
            tables.add(tableInfo);
        }

        return tables;
    }

    /**
     * 获取API端点信息列表
     */
    private List<ApiEndpointInfo> getApiEndpointList(Long projectId, List<Long> tableIds) {
        LambdaQueryWrapper<GenApiEndpoint> query = new LambdaQueryWrapper<>();
        query.eq(GenApiEndpoint::getProjectId, projectId)
             .in(GenApiEndpoint::getTableId, tableIds);
        
        List<GenApiEndpoint> endpoints = apiEndpointMapper.selectList(query);
        
        return endpoints.stream().map(this::convertToEndpointInfo).collect(Collectors.toList());
    }

    /**
     * 生成代码文件
     */
    private Map<String, String> generateCodeFiles(CodeGenerationRequest request, List<TableInfo> tables, List<ApiEndpointInfo> endpoints) {
        Map<String, String> files = new HashMap<>();
        
        for (TableInfo table : tables) {
            String className = convertToClassName(table.getTableName());
            String packagePath = request.getPackageName().replace(".", "/");
            
            // 生成Entity
            if (request.getConfig().getGenerateEntity()) {
                String entityCode = generateEntityCode(request, table);
                files.put("src/main/java/" + packagePath + "/entity/" + className + ".java", entityCode);
            }
            
            // 生成DTO
            if (request.getConfig().getGenerateDto()) {
                String dtoCode = generateDtoCode(request, table);
                files.put("src/main/java/" + packagePath + "/dto/" + className + "DTO.java", dtoCode);
            }
            
            // 生成VO
            if (request.getConfig().getGenerateVo()) {
                String voCode = generateVoCode(request, table);
                files.put("src/main/java/" + packagePath + "/vo/" + className + "VO.java", voCode);
            }
            
            // 生成Mapper
            if (request.getConfig().getGenerateMapper()) {
                String mapperCode = generateMapperCode(request, table);
                files.put("src/main/java/" + packagePath + "/mapper/" + className + "Mapper.java", mapperCode);
                
                String mapperXml = generateMapperXml(request, table);
                files.put("src/main/resources/mapper/" + className + "Mapper.xml", mapperXml);
            }
            
            // 生成Service
            if (request.getConfig().getGenerateService()) {
                String serviceInterface = generateServiceInterface(request, table);
                files.put("src/main/java/" + packagePath + "/service/I" + className + "Service.java", serviceInterface);
                
                String serviceImpl = generateServiceImpl(request, table);
                files.put("src/main/java/" + packagePath + "/service/impl/" + className + "ServiceImpl.java", serviceImpl);
            }
            
            // 生成Controller
            if (request.getConfig().getGenerateController()) {
                String controllerCode = generateControllerCode(request, table);
                files.put("src/main/java/" + packagePath + "/controller/" + className + "Controller.java", controllerCode);
            }
        }
        
        // 生成配置文件
        if (request.getConfig().getGenerateConfig()) {
            files.put("src/main/resources/application.yml", generateApplicationYml(request));
            files.put("pom.xml", generatePomXml(request));
        }
        
        // 生成主类
        files.put("src/main/java/" + request.getPackageName().replace(".", "/") + "/Application.java", 
                 generateMainClass(request));
        
        return files;
    }

    /**
     * 生成Entity代码
     */
    private String generateEntityCode(CodeGenerationRequest request, TableInfo table) {
        StringBuilder code = new StringBuilder();
        String className = convertToClassName(table.getTableName());
        
        code.append("package ").append(request.getPackageName()).append(".entity;\n\n");
        code.append("import com.baomidou.mybatisplus.annotation.*;\n");
        if (request.getConfig().getUseLombok()) {
            code.append("import lombok.Data;\n");
        }
        code.append("import java.time.LocalDateTime;\n");
        code.append("import java.math.BigDecimal;\n\n");
        
        code.append("/**\n");
        code.append(" * ").append(table.getTableComment()).append("\n");
        code.append(" *\n");
        code.append(" * @author ").append(request.getAuthor()).append("\n");
        code.append(" */\n");
        
        if (request.getConfig().getUseLombok()) {
            code.append("@Data\n");
        }
        code.append("@TableName(\"").append(table.getTableName()).append("\")\n");
        code.append("public class ").append(className).append(" {\n\n");
        
        for (FieldInfo field : table.getFields()) {
            code.append("    /**\n");
            code.append("     * ").append(field.getFieldComment()).append("\n");
            code.append("     */\n");
            
            if (field.getIsPrimaryKey()) {
                code.append("    @TableId(value = \"").append(field.getFieldName()).append("\", type = IdType.AUTO)\n");
            } else {
                code.append("    @TableField(\"").append(field.getFieldName()).append("\")\n");
            }
            
            code.append("    private ").append(field.getJavaType()).append(" ")
                .append(convertToCamelCase(field.getFieldName())).append(";\n\n");
        }
        
        code.append("}\n");
        
        return code.toString();
    }

    /**
     * 生成其他代码方法（简化实现）
     */
    private String generateDtoCode(CodeGenerationRequest request, TableInfo table) {
        return "// DTO代码生成 - " + table.getTableName();
    }

    private String generateVoCode(CodeGenerationRequest request, TableInfo table) {
        return "// VO代码生成 - " + table.getTableName();
    }

    private String generateMapperCode(CodeGenerationRequest request, TableInfo table) {
        return "// Mapper代码生成 - " + table.getTableName();
    }

    private String generateMapperXml(CodeGenerationRequest request, TableInfo table) {
        return "<!-- Mapper XML生成 - " + table.getTableName() + " -->";
    }

    private String generateServiceInterface(CodeGenerationRequest request, TableInfo table) {
        return "// Service接口生成 - " + table.getTableName();
    }

    private String generateServiceImpl(CodeGenerationRequest request, TableInfo table) {
        return "// Service实现生成 - " + table.getTableName();
    }

    private String generateServiceCode(CodeGenerationRequest request, TableInfo table) {
        return "// Service代码生成 - " + table.getTableName();
    }

    private String generateControllerCode(CodeGenerationRequest request, TableInfo table) {
        return "// Controller代码生成 - " + table.getTableName();
    }

    private String generateApplicationYml(CodeGenerationRequest request) {
        return "# 应用配置文件\nserver:\n  port: 8080\n";
    }

    private String generatePomXml(CodeGenerationRequest request) {
        return "<!-- POM配置文件 -->\n<project>...</project>";
    }

    private String generateMainClass(CodeGenerationRequest request) {
        return "// 主启动类\npackage " + request.getPackageName() + ";\n\n" +
               "@SpringBootApplication\npublic class Application {\n" +
               "    public static void main(String[] args) {\n" +
               "        SpringApplication.run(Application.class, args);\n" +
               "    }\n}\n";
    }

    /**
     * 创建项目压缩包
     */
    private String createProjectArchive(String projectCode, Map<String, String> files) {
        // TODO: 实现文件压缩逻辑
        return "/downloads/" + projectCode + "_" + System.currentTimeMillis() + ".zip";
    }

    /**
     * 保存生成记录
     */
    private Long saveGenerationRecord(CodeGenerationRequest request, int tableCount, int endpointCount) {
        // TODO: 实现生成记录保存
        return System.currentTimeMillis();
    }

    /**
     * 转换为字段信息
     */
    private FieldInfo convertToFieldInfo(GenTableField field) {
        FieldInfo fieldInfo = new FieldInfo();
        fieldInfo.setFieldName(field.getFieldName());
        fieldInfo.setFieldType(field.getFieldType());
        fieldInfo.setFieldComment(field.getFieldComment());
        fieldInfo.setIsPrimaryKey(field.getIsPrimaryKey());
        fieldInfo.setIsNullable(field.getIsNullable());
        fieldInfo.setJavaType(getJavaType(field.getFieldType()));
        return fieldInfo;
    }

    /**
     * 转换为端点信息
     */
    private ApiEndpointInfo convertToEndpointInfo(GenApiEndpoint endpoint) {
        ApiEndpointInfo info = new ApiEndpointInfo();
        info.setEndpointPath(endpoint.getEndpointPath());
        info.setHttpMethod(endpoint.getHttpMethod());
        info.setEndpointName(endpoint.getEndpointName());
        info.setDescription(endpoint.getDescription());
        return info;
    }

    /**
     * 转换为类名
     */
    private String convertToClassName(String tableName) {
        // 移除前缀并转换为驼峰命名
        String className = tableName;
        if (className.startsWith("sys_")) {
            className = className.substring(4);
        } else if (className.startsWith("gen_")) {
            className = className.substring(4);
        }
        
        return convertToPascalCase(className);
    }

    /**
     * 转换为驼峰命名
     */
    private String convertToCamelCase(String str) {
        String[] parts = str.split("_");
        StringBuilder result = new StringBuilder(parts[0].toLowerCase());
        for (int i = 1; i < parts.length; i++) {
            result.append(parts[i].substring(0, 1).toUpperCase())
                  .append(parts[i].substring(1).toLowerCase());
        }
        return result.toString();
    }

    /**
     * 转换为帕斯卡命名
     */
    private String convertToPascalCase(String str) {
        String camelCase = convertToCamelCase(str);
        return camelCase.substring(0, 1).toUpperCase() + camelCase.substring(1);
    }

    /**
     * 获取Java类型
     */
    private String getJavaType(String sqlType) {
        switch (sqlType.toUpperCase()) {
            case "BIGINT":
                return "Long";
            case "INT":
            case "INTEGER":
                return "Integer";
            case "VARCHAR":
            case "TEXT":
                return "String";
            case "DATETIME":
            case "TIMESTAMP":
                return "LocalDateTime";
            case "DECIMAL":
                return "BigDecimal";
            case "TINYINT":
                return "Boolean";
            default:
                return "String";
        }
    }

    // 内部类定义
    private static class TableInfo {
        private Long tableId;
        private String tableName;
        private String tableComment;
        private List<FieldInfo> fields;
        
        // getters and setters
        public Long getTableId() { return tableId; }
        public void setTableId(Long tableId) { this.tableId = tableId; }
        public String getTableName() { return tableName; }
        public void setTableName(String tableName) { this.tableName = tableName; }
        public String getTableComment() { return tableComment; }
        public void setTableComment(String tableComment) { this.tableComment = tableComment; }
        public List<FieldInfo> getFields() { return fields; }
        public void setFields(List<FieldInfo> fields) { this.fields = fields; }
    }

    private static class FieldInfo {
        private String fieldName;
        private String fieldType;
        private String fieldComment;
        private Boolean isPrimaryKey;
        private Boolean isNullable;
        private String javaType;
        
        // getters and setters
        public String getFieldName() { return fieldName; }
        public void setFieldName(String fieldName) { this.fieldName = fieldName; }
        public String getFieldType() { return fieldType; }
        public void setFieldType(String fieldType) { this.fieldType = fieldType; }
        public String getFieldComment() { return fieldComment; }
        public void setFieldComment(String fieldComment) { this.fieldComment = fieldComment; }
        public Boolean getIsPrimaryKey() { return isPrimaryKey; }
        public void setIsPrimaryKey(Boolean isPrimaryKey) { this.isPrimaryKey = isPrimaryKey; }
        public Boolean getIsNullable() { return isNullable; }
        public void setIsNullable(Boolean isNullable) { this.isNullable = isNullable; }
        public String getJavaType() { return javaType; }
        public void setJavaType(String javaType) { this.javaType = javaType; }
    }

    private static class ApiEndpointInfo {
        private String endpointPath;
        private String httpMethod;
        private String endpointName;
        private String description;
        
        // getters and setters
        public String getEndpointPath() { return endpointPath; }
        public void setEndpointPath(String endpointPath) { this.endpointPath = endpointPath; }
        public String getHttpMethod() { return httpMethod; }
        public void setHttpMethod(String httpMethod) { this.httpMethod = httpMethod; }
        public String getEndpointName() { return endpointName; }
        public void setEndpointName(String endpointName) { this.endpointName = endpointName; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }
}











